#include "DWGReader.h"
#include "scene.h"
#include <osg/MatrixTransform>
#include <osg/Group>
#include <osgText/Text>
#include <osgText/Font>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osg/Notify>
#include <osgUtil/Tessellator>
#include <cmath>
#include <chrono>
#include "Utils.h"
using namespace osg;

// Register the plugin
REGISTER_OSGPLUGIN(dwg, DWGReader)

DWGReader::DWGReader()
{
    supportsExtension("dwg", "AutoCAD DWG format");
    font_ = osgText::readFontFile("fonts/arial.ttf");
}

bool DWGReader::acceptsExtension(const std::string &extension) const
{
    return osgDB::equalCaseInsensitive(extension, "dwg");
}

osgDB::ReaderWriter::ReadResult
DWGReader::readNode(const std::string &fileName, const osgDB::ReaderWriter::Options *options) const
{
    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
    if (!acceptsExtension(ext))
        return ReadResult::FILE_NOT_HANDLED;

    std::string foundFileName = osgDB::findDataFile(fileName, options);
    if (foundFileName.empty())
        return ReadResult::FILE_NOT_FOUND;

    OSG_INFO << "DWGReader::readNode(" << foundFileName << ")" << std::endl;

    // Initialize libredwg
    Dwg_Data dwg;
    memset(&dwg, 0, sizeof(Dwg_Data));
    dwg.opts =  0;
    auto start = std::chrono::high_resolution_clock::now();
    int result = dwg_read_file(foundFileName.c_str(), &dwg);
    auto end = std::chrono::high_resolution_clock::now();
    // 计算持续时间
    int64_t ms_int64 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    OSG_ALWAYS<< "加载dwg执行时间: " << ms_int64  << " 毫秒" << std::endl;
    if (result >= DWG_ERR_CRITICAL)
    {
        OSG_WARN << "Failed to read DWG file: " << foundFileName << std::endl;
        return ReadResult::ERROR_IN_READING_FILE;
    }

    // Get model space
    Dwg_Object_Ref *modelSpaceRef = dwg_model_space_ref(&dwg);
    if (!modelSpaceRef)
    {
        OSG_WARN << "No model space found in DWG file" << std::endl;
        dwg_free(&dwg);
        return ReadResult::ERROR_IN_READING_FILE;
    }

    Dwg_Object *modelSpace = dwg_ref_object(&dwg, modelSpaceRef);
    if (!modelSpace)
    {
        OSG_WARN << "Failed to resolve model space object" << std::endl;
        dwg_free(&dwg);
        return ReadResult::ERROR_IN_READING_FILE;
    }
    start = std::chrono::high_resolution_clock::now();
    // Create DwgScene
    ref_ptr<DwgScene> dwgScene = new DwgScene;

    // Process entities
    Dwg_Object *entity = get_first_owned_entity(modelSpace);
    while (entity)
    {
        if (entity->type >= DWG_TYPE_TEXT && entity->type <= DWG_TYPE_UNKNOWN_ENT)
        {
            convertEntityToScene(entity, &dwg, dwgScene.get());
        }
        entity = get_next_owned_entity(modelSpace, entity);
    }
    end = std::chrono::high_resolution_clock::now();
    // 计算持续时间
    int64_t ms_int64_1 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    OSG_ALWAYS<< "dwg转osg1执行时间: " << ms_int64_1  << " 毫秒" << std::endl;

    start = std::chrono::high_resolution_clock::now();
    // Convert DwgScene to OSG nodes
    ref_ptr<Group> root = dwgScene->scene2osg();

    // Cleanup
    dwg_free(&dwg);
    end = std::chrono::high_resolution_clock::now();
    // 计算持续时间
    int64_t ms_int64_2 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    OSG_ALWAYS<< "dwg转osg2执行时间: " << ms_int64_2  << " 毫秒" << std::endl;
    if (root.valid())
    {
        return ReadResult(root.get());
    }
    else
    {
        return ReadResult::ERROR_IN_READING_FILE;
    }
}

void DWGReader::convertEntityToScene(Dwg_Object *entity, Dwg_Data *dwg, DwgScene *dwgScene) const
{
    if (!entity || !entity->tio.entity)
        return;

    // Get layer name
    std::string layerName = "0"; // default layer
    if (entity->tio.entity->layer)
    {
        Dwg_Object *layerObj = dwg_ref_object(dwg, entity->tio.entity->layer);
        if (layerObj && layerObj->fixedtype == DWG_TYPE_LAYER)
        {
            Dwg_Object_LAYER *layer = layerObj->tio.object->tio.LAYER;
            if (layer && layer->name)
            {

                if (dwg->header.version >= R_2007)
                {
                    char *u8 = bit_convert_TU((BITCODE_TU)layer->name);
                    if (u8)
                    {
                        layerName = u8;
                        free(u8);
                    }
                }
                else
                {
                    layerName = std::string(layer->name);
                }
            }
        }
    }

    // Get color
    Vec4 color = convertColor(entity->tio.entity, dwg);

    switch (entity->type)
    {
    case DWG_TYPE_LINE:
        convertLineToScene(entity->tio.entity->tio.LINE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_CIRCLE:
        convertCircleToScene(entity->tio.entity->tio.CIRCLE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_ARC:
        convertArcToScene(entity->tio.entity->tio.ARC, layerName, color, dwgScene);
        break;
    case DWG_TYPE_TEXT:
        convertTextToScene(entity->tio.entity->tio.TEXT, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_LWPOLYLINE:
        convertLWPolylineToScene(entity->tio.entity->tio.LWPOLYLINE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_POLYLINE_2D:
        convertPolyline2DToScene(entity, layerName, color, dwgScene, dwg);
        break;
    // 新增实体类型支持
    case DWG_TYPE_POINT:
        convertPointToScene(entity->tio.entity->tio.POINT, layerName, color, dwgScene);
        break;
    case DWG_TYPE_SOLID:
        convertSolidToScene(entity->tio.entity->tio.SOLID, layerName, color, dwgScene);
        break;
    case DWG_TYPE__3DFACE:
        convert3DFaceToScene(entity->tio.entity->tio._3DFACE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_POLYLINE_PFACE:
        convertPolylinePFaceToScene(entity, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_INSERT:
        convertInsertToScene(entity->tio.entity->tio.INSERT, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_ATTRIB:
        convertAttribToScene(entity->tio.entity->tio.ATTRIB, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_MTEXT:
        convertMTextToScene(entity->tio.entity->tio.MTEXT, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_HATCH:
        convertHatchToScene(entity->tio.entity->tio.HATCH, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE__3DSOLID:
        convert3DSolidToScene(entity->tio.entity->tio._3DSOLID, layerName, color, dwgScene);
        break;
    case DWG_TYPE_REGION:
        convertRegionToScene(entity->tio.entity->tio.REGION, layerName, color, dwgScene);
        break;
    case DWG_TYPE_DIMENSION_LINEAR:
        convertDimensionLinearToScene(entity->tio.entity->tio.DIMENSION_LINEAR, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_DIMENSION_ALIGNED:
        convertDimensionAlignedToScene(entity->tio.entity->tio.DIMENSION_ALIGNED, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_DIMENSION_ANG2LN:
        convertDimensionAng2LnToScene(entity->tio.entity->tio.DIMENSION_ANG2LN, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_DIMENSION_ORDINATE:
        convertDimensionOrdinateToScene(entity->tio.entity->tio.DIMENSION_ORDINATE, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_SPLINE:
        convertSplineToScene(entity->tio.entity->tio.SPLINE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_XLINE:
        convertXLineToScene(entity->tio.entity->tio.XLINE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_RAY:
        convertRayToScene(entity->tio.entity->tio.RAY, layerName, color, dwgScene);
        break;
    case DWG_TYPE_POLYLINE_3D:
        convertPolyline3DToScene(entity, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_ELLIPSE:
        convertEllipseToScene(entity->tio.entity->tio.ELLIPSE, layerName, color, dwgScene);
        break;
    case DWG_TYPE_MLINE:
        convertMLineToScene(entity->tio.entity->tio.MLINE, layerName, color, dwgScene, dwg);
        break;
    case DWG_TYPE_TOLERANCE:
        convertToleranceToScene(entity->tio.entity->tio.TOLERANCE, layerName, color, dwgScene);
        break;
    // Add more entity types as needed
    default:
        OSG_DEBUG << "Unsupported entity type: " << entity->type << std::endl;
        break;
    }
}

void DWGReader::convertLineToScene(Dwg_Entity_LINE *line, const std::string &layerName,
                                   const Vec4 &color, DwgScene *dwgScene) const
{
    if (!line)
        return;

    Vec3d start(line->start.x, line->start.y, line->start.z);
    Vec3d end(line->end.x, line->end.y, line->end.z);
    dwgScene->addLine(layerName, color, start, end);
}

void DWGReader::convertCircleToScene(Dwg_Entity_CIRCLE *circle, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene) const
{
    if (!circle)
        return;

    Vec3d center(circle->center.x, circle->center.y, circle->center.z);

    // Create a circle as a line loop
    const int segments = 32;
    std::vector<Vec3d> vertices;
    double radius = circle->radius;

    for (int i = 0; i <= segments; ++i)
    {
        double angle = (2.0 * M_PI * i) / segments;
        Vec3d point(
            center.x() + radius * cos(angle),
            center.y() + radius * sin(angle),
            center.z());
        vertices.push_back(point);
    }

    dwgScene->addLineLoop(layerName, color, vertices);
}

void DWGReader::convertArcToScene(Dwg_Entity_ARC *arc, const std::string &layerName,
                                  const Vec4 &color, DwgScene *dwgScene) const
{
    if (!arc)
        return;

    Vec3d center(arc->center.x, arc->center.y, arc->center.z);

    // Create an arc as a line strip
    const int segments = 32;
    std::vector<Vec3d> vertices;
    double radius = arc->radius;
    double startAngle = arc->start_angle;
    double endAngle = arc->end_angle;

    // Handle full circle case
    if (startAngle == endAngle)
    {
        endAngle = startAngle + 2.0 * M_PI;
    }

    // Ensure proper angle direction
    if (endAngle < startAngle)
    {
        endAngle += 2.0 * M_PI;
    }

    for (int i = 0; i <= segments; ++i)
    {
        double t = (double)i / segments;
        double angle = startAngle + t * (endAngle - startAngle);
        Vec3d point(
            center.x() + radius * cos(angle),
            center.y() + radius * sin(angle),
            center.z());
        vertices.push_back(point);
    }

    dwgScene->addLineStrip(layerName, color, vertices);
}

void DWGReader::convertTextToScene(Dwg_Entity_TEXT *text, const std::string &layerName,
                                   const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!text)
        return;

    // Create OSG text
    ref_ptr<osgText::Text> osgText = new osgText::Text;

    // Set font
    osgText->setFont(font_);

    // Set text content
    if (text->text_value)
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)text->text_value);
            if (u8)
            {
                osgText->setText(std::string(u8));
                free(u8);
            }
        }
        else
        {
            osgText->setText(std::string(text->text_value));
        }
    }

    // Set position
    Vec3d position(text->ins_pt.x, text->ins_pt.y, text->elevation);

    // Set character size
    osgText->setCharacterSize(text->height > 0 ? text->height : 1.0);

    // Set color
    osgText->setColor(color);

    // Set rotation if present
    if (text->rotation != 0.0)
    {
        osgText->setRotation(osg::Quat(text->rotation, osg::Vec3d(0,0,1)));
    }

    dwgScene->addText(layerName, color, position, osgText);
}

void DWGReader::convertLWPolylineToScene(Dwg_Entity_LWPOLYLINE *polyline, const std::string &layerName,
                                         const Vec4 &color, DwgScene *dwgScene) const
{
    if (!polyline || polyline->num_points == 0)
        return;

    std::vector<Vec3d> vertices;

    // Extract vertices
    for (unsigned int i = 0; i < polyline->num_points; ++i)
    {
        BITCODE_2RD point = polyline->points[i];
        Vec3d vertex(point.x, point.y, polyline->elevation); // LWPOLYLINE is 2D, Z is 0
        vertices.push_back(vertex);
    }

    // Handle closed polyline
    if (polyline->flag & 512)
    { // Closed polyline
        dwgScene->addLineLoop(layerName, color, vertices);
    }
    else
    {
        dwgScene->addLineStrip(layerName, color, vertices);
    }
}

void DWGReader::convertPolyline2DToScene(Dwg_Object *entity, const std::string &layerName,
                                         const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!entity)
        return;
    if (!entity->tio.entity||!entity->tio.entity->tio.POLYLINE_2D)
        return;
    std::vector<Vec3d> vertices;
    Dwg_Entity_POLYLINE_2D *polyline = entity->tio.entity->tio.POLYLINE_2D;
    // Extract vertices from owned entities
    Dwg_Object *vertexObj = get_first_owned_subentity(entity);
    while (vertexObj)
    {
        if (vertexObj->fixedtype == DWG_TYPE_VERTEX_2D&& vertexObj->tio.entity->tio.VERTEX_2D)
        {
            Dwg_Entity_VERTEX_2D *vertex = vertexObj->tio.entity->tio.VERTEX_2D;
            Vec3d point(vertex->point.x, vertex->point.y, vertex->point.z);
            vertices.push_back(point);
        }
        vertexObj = get_next_owned_subentity(entity, vertexObj);
    }

    if (vertices.empty())
        return;

    // Handle closed polyline
    if (polyline->flag & 1)
    { // Closed polyline
        dwgScene->addLineLoop(layerName, color, vertices);
    }
    else
    {
        dwgScene->addLineStrip(layerName, color, vertices);
    }
}

// 新增实体类型转换函数实现
void DWGReader::convertPointToScene(Dwg_Entity_POINT *point, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene) const
{
    if (!point)
        return;

    Vec3d position(point->x, point->y, point->z);
    dwgScene->addPoint(layerName, color, position);
}

void DWGReader::convertSolidToScene(Dwg_Entity_SOLID *solid, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene) const
{
    if (!solid)
        return;

    std::vector<Vec3d> vertices;

    // Add corners (1, 2, 3, 4) - note that SOLID may be triangle or quad
    Vec3d p0(solid->corner1.x, solid->corner1.y, 0);
    Vec3d p1(solid->corner2.x, solid->corner2.y, 0);
    Vec3d p2(solid->corner3.x, solid->corner3.y, 0);
    Vec3d p3(solid->corner4.x, solid->corner4.y, 0);

    bool bquad = (solid->corner4.x != solid->corner1.x ||
                  solid->corner4.y != solid->corner1.y);

    if (!bquad)
    {
        vertices.push_back(p0);
        vertices.push_back(p1);
        vertices.push_back(p2);
    }
    else
    {
        osg::Vec3 ip;
        bool binter = computeIntersection2D(p0, p2, p1, p3, ip);

        if (binter)
        {
            // ========== AutoCAD 的拆分方式 ==========
            vertices.push_back(ip);
            vertices.push_back(p0);
            vertices.push_back(p1);
            vertices.push_back(ip);
            vertices.push_back(p2);
            vertices.push_back(p3);
        }
        else
        {
            // ========== 退化为普通四边形 ==========
            vertices.push_back(p0);
            vertices.push_back(p1);
            vertices.push_back(p2);
            vertices.push_back(p3);
        }
    }
    // Create face from vertices
    dwgScene->addFace(layerName, vertices, color);
}

void DWGReader::convert3DFaceToScene(Dwg_Entity__3DFACE *face, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene) const
{
    if (!face)
        return;

    std::vector<Vec3d> vertices;

    // Add the four corners of the 3D face
    vertices.push_back(Vec3d(face->corner1.x, face->corner1.y, face->corner1.z));
    vertices.push_back(Vec3d(face->corner2.x, face->corner2.y, face->corner2.z));
    vertices.push_back(Vec3d(face->corner3.x, face->corner3.y, face->corner3.z));

    // Check if the fourth corner is distinct from the third
    Vec3d corner4(face->corner4.x, face->corner4.y, face->corner4.z);
    Vec3d corner3(face->corner3.x, face->corner3.y, face->corner3.z);

    // Use small threshold for comparison instead of direct equality
    if ((corner4 - corner3).length() > 1e-10)
    {
        vertices.push_back(corner4);
    }

    // Create face from vertices
    dwgScene->addFace(layerName, vertices, color);
}

void DWGReader::convertPolylinePFaceToScene(Dwg_Object *entity, const std::string &layerName,
                                            const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!entity)
        return;
    if (!entity->tio.entity->tio.POLYLINE_PFACE)
        return;

    std::vector<Vec3d> vertices;
    std::vector<std::vector<int>> faces;

    // Use get_first_owned_subentity/get_next_owned_subentity to get sub-entities
    Dwg_Object *vertexObj = get_first_owned_subentity(entity);
    while (vertexObj)
    {
        // Process vertex coordinates
        if (vertexObj->fixedtype == DWG_TYPE_VERTEX_PFACE && vertexObj->tio.entity->tio.VERTEX_PFACE)
        {
            Dwg_Entity_VERTEX_PFACE *vertex = vertexObj->tio.entity->tio.VERTEX_PFACE;
            Vec3d point(vertex->point.x, vertex->point.y, vertex->point.z);
            vertices.push_back(point);
        }
        // Process face definitions
        else if (vertexObj->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE && vertexObj->tio.entity->tio.VERTEX_PFACE_FACE)
        {
            Dwg_Entity_VERTEX_PFACE_FACE *face = vertexObj->tio.entity->tio.VERTEX_PFACE_FACE;
            std::vector<int> faceIndices;

            // Collect face vertex indices
            for (int i = 0; i < 4; i++)
            {
                int index = face->vertind[i];
                if (index > 0)
                {                                     // 0 means the vertex is not used
                    faceIndices.push_back(index - 1); // Convert to 0-based index
                }
            }

            if (!faceIndices.empty())
            {
                faces.push_back(faceIndices);
            }
        }

        vertexObj = get_next_owned_subentity(entity, vertexObj);
    }

    // Create faces from the collected data
    for (std::vector<std::vector<int>>::const_iterator fitr = faces.begin();
         fitr != faces.end(); ++fitr)
    {
        std::vector<Vec3d> faceVertices;
        for (std::vector<int>::const_iterator iitr = (*fitr).begin();
             iitr != (*fitr).end(); ++iitr)
        {
            if (*iitr >= 0 && *iitr < (int)vertices.size())
            {
                faceVertices.push_back(vertices[*iitr]);
            }
        }
        if (!faceVertices.empty())
        {
            dwgScene->addLineLoop(layerName, color, faceVertices);
        }
    }

    // If only vertices without faces, draw as points
    if (vertices.size() > 0 && faces.empty())
    {
        for (std::vector<Vec3d>::const_iterator vitr = vertices.begin();
             vitr != vertices.end(); ++vitr)
        {
            Vec3d point = *vitr;
            dwgScene->addPoint(layerName, color, point);
        }
    }
}

void DWGReader::convertInsertToScene(Dwg_Entity_INSERT *insert, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!insert)
        return;

    // Get the block header
    Dwg_Object *blockHeaderObj = dwg_ref_object(dwg, insert->block_header);
    if (!blockHeaderObj || blockHeaderObj->fixedtype != DWG_TYPE_BLOCK_HEADER)
        return;

    Dwg_Object_BLOCK_HEADER *blockHeader = blockHeaderObj->tio.object->tio.BLOCK_HEADER;

    // Save current transformation matrix
    Matrixd transformMatrix;
    transformMatrix.setTrans(Vec3d(insert->ins_pt.x, insert->ins_pt.y, insert->ins_pt.z));

    // Apply scale if present
    if (insert->has_attribs)
    {
        Matrixd scaleMatrix;
        scaleMatrix.makeScale(insert->scale.x, insert->scale.y, insert->scale.z);
        transformMatrix.preMult(scaleMatrix);
    }

    // Apply rotation if present
    if (insert->rotation != 0.0)
    {
        Matrixd rotationMatrix;
        rotationMatrix.makeRotate(insert->rotation, Vec3(0, 0, 1));
        transformMatrix.preMult(rotationMatrix);
    }

    // Push the transformation to the DwgScene
    dwgScene->pushMatrix(transformMatrix);

    // Process entities in the block
    Dwg_Object *blockEntity = get_first_owned_entity(blockHeaderObj);
    while (blockEntity)
    {
        convertEntityToScene(blockEntity, dwg, dwgScene);
        blockEntity = get_next_owned_entity(blockHeaderObj, blockEntity);
    }

    // Pop the transformation from the DwgScene
    dwgScene->popMatrix();

    // 处理 INSERT 实体的属性 (ATTRIB)
    if (insert->has_attribs)
    {
        // 创建组来包含 INSERT 对象和其属性

        // 方法1: 使用 first_attrib/last_attrib 链表方式 (R13-R2000)
        if (dwg->header.version >= R_13b1 && dwg->header.version <= R_2000)
        {
            Dwg_Object *attribObj = insert->first_attrib ? dwg_ref_object(dwg, insert->first_attrib) : nullptr;
            Dwg_Object *lastAttribObj = insert->last_attrib ? dwg_ref_object(dwg, insert->last_attrib) : nullptr;

            while (attribObj && attribObj->fixedtype == DWG_TYPE_ATTRIB)
            {
                convertEntityToScene(attribObj, dwg, dwgScene);

                // 移动到下一个属性
                if (attribObj == lastAttribObj)
                    break;

                // 获取下一个实体并检查是否为 ATTRIB 类型
                attribObj = dwg_next_entity(attribObj);
                if (!attribObj || attribObj->fixedtype != DWG_TYPE_ATTRIB)
                    break;
            }
        }
        // 方法2: 使用 attribs 数组方式 (R2004+ 和 R11)
        else if ((dwg->header.version >= R_2004 || dwg->header.version < R_13b1) && insert->num_owned > 0)
        {
            for (BITCODE_BL i = 0; i < insert->num_owned; i++)
            {
                if (insert->attribs && insert->attribs[i])
                {
                    Dwg_Object *attribObj = dwg_ref_object(dwg, insert->attribs[i]);
                    if (attribObj && attribObj->fixedtype == DWG_TYPE_ATTRIB)
                    {
                        convertEntityToScene(attribObj, dwg, dwgScene);
                    }
                }
            }
        }
    }
}

void DWGReader::convertAttribToScene(Dwg_Entity_ATTRIB *attrib, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!attrib)
        return;

    // Create OSG text
    ref_ptr<osgText::Text> osgText = new osgText::Text;

    // Set font
    osgText->setFont(font_);

    // Set text content
    std::string textContent;
    if (attrib->text_value)
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)attrib->text_value);
            if (u8)
            {
                textContent = std::string(u8);
                free(u8);
            }
        }
        else
        {
            textContent = std::string(attrib->text_value);
        }
    }

    // Get tag
    // std::string tag = attrib->tag ? std::string(attrib->tag) : "UNNAMED";

    // Display as "tag = value"
    std::string displayText = textContent;
    osgText->setText(displayText);

    // Set position
    Vec3d position(attrib->ins_pt.x, attrib->ins_pt.y, attrib->elevation);

    // Set character size
    osgText->setCharacterSize(attrib->height > 0 ? attrib->height : 1.0);

    // Set color
    osgText->setColor(color);

    // Set rotation if present
    if (attrib->rotation != 0.0)
    {
        // Matrix rotationMatrix;
        // rotationMatrix.makeRotate(attrib->rotation, Vec3(0, 0, 1));
        // osgText->setRotation(Quat(rotationMatrix.getRotate()));
        osgText->setRotation(osg::Quat(attrib->rotation, osg::Vec3d(0,0,1)));
    }

    dwgScene->addText(layerName, color, position, osgText);
}

void DWGReader::convertMTextToScene(Dwg_Entity_MTEXT *mtext, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!mtext)
        return;

    // Create OSG text
    ref_ptr<osgText::Text> osgText = new osgText::Text;

    // Set font
    osgText->setFont(font_);

    // Set text content
    std::string textContent;
    if (mtext->text)
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)mtext->text);
            if (u8)
            {
                textContent = std::string(u8);
                free(u8);
            }
        }
        else
        {
            textContent = std::string(mtext->text);
        }
    }
    textContent = processMTextFormatting(textContent);
    osgText->setText(textContent);

    // Set position
    Vec3d position(mtext->ins_pt.x, mtext->ins_pt.y, mtext->ins_pt.z);

    // Set character size
    osgText->setCharacterSize(mtext->text_height > 0 ? mtext->text_height : 1.0);

    // Set color
    osgText->setColor(color);

    dwgScene->addText(layerName, color, position, osgText);
}

void DWGReader::convertHatchToScene(Dwg_Entity_HATCH *hatch, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!hatch)
        return;

    // Create boundary paths
    std::vector<std::vector<Vec3d>> boundaryPaths;

    for (BITCODE_BL i = 0; i < hatch->num_paths; i++)
    {
        Dwg_HATCH_Path *path = &hatch->paths[i];
        std::vector<Vec3d> points;

        // Process polyline path
        if (path->flag & 2)
        { // Polyline path
            for (BITCODE_BL j = 0; j < path->num_segs_or_paths; j++)
            {
                if (path->polyline_paths && j < path->num_segs_or_paths)
                {
                    Dwg_HATCH_PolylinePath *polyPt = &path->polyline_paths[j];
                    points.push_back(Vec3d(polyPt->point.x, polyPt->point.y, 0.0));
                }
            }

            // Close path if not open
            if (!points.empty() && (path->flag & 0x20) == 0)
            { // Not open
                points.push_back(points[0]);
            }
        }
        // Process line segment path
        else
        {
            for (BITCODE_BL j = 0; j < path->num_segs_or_paths; j++)
            {
                if (path->segs && j < path->num_segs_or_paths)
                {
                    Dwg_HATCH_PathSeg *seg = &path->segs[j];
                    // Process line segment
                    if (seg->curve_type == 1)
                    { // Line segment
                        points.push_back(Vec3d(seg->first_endpoint.x, seg->first_endpoint.y, 0.0));
                        // Add second point only if it's the last segment or points are different
                        if (j == path->num_segs_or_paths - 1 ||
                            (seg->second_endpoint.x != seg->first_endpoint.x ||
                             seg->second_endpoint.y != seg->first_endpoint.y))
                        {
                            points.push_back(Vec3d(seg->second_endpoint.x, seg->second_endpoint.y, 0.0));
                        }
                    }
                }
            }
        }

        if (!points.empty())
        {
            boundaryPaths.push_back(points);
        }
    }

    // Draw boundaries
    for (std::vector<std::vector<Vec3d>>::iterator pathItr = boundaryPaths.begin();
         pathItr != boundaryPaths.end(); ++pathItr)
    {
        if (!(*pathItr).empty())
        {
            dwgScene->addLineLoop(layerName, color, *pathItr);
        }
    }

    // Handle solid fill
    if (!boundaryPaths.empty() && hatch->is_solid_fill)
    {
        // For solid fill, we use osgUtil::Tessellator to triangulate
        for (std::vector<std::vector<Vec3d>>::const_iterator pathItr = boundaryPaths.begin();
             pathItr != boundaryPaths.end(); ++pathItr)
        {
            if ((*pathItr).size() >= 3)
            {
                // Add solid fill as triangles
                dwgScene->addFace(layerName, *pathItr, color);
            }
        }
    }
}

void DWGReader::convert3DSolidToScene(Dwg_Entity__3DSOLID *solid, const std::string &layerName,
                                      const Vec4 &color, DwgScene *dwgScene) const
{
    if (!solid)
        return;

    // If we have wireframe data, use it for visualization
    if (solid->num_wires > 0 && solid->wires)
    {
        for (BITCODE_BL i = 0; i < solid->num_wires; i++)
        {
            Dwg_3DSOLID_wire *wire = &solid->wires[i];
            if (wire->num_points > 0 && wire->points)
            {
                std::vector<Vec3d> vertices;
                for (BITCODE_BL j = 0; j < wire->num_points; j++)
                {
                    vertices.push_back(Vec3d(wire->points[j].x, wire->points[j].y, wire->points[j].z));
                }
                dwgScene->addLineStrip(layerName, color, vertices);
            }
        }
    }
    // If we have point data
    else if (solid->point_present)
    {
        Vec3d point(solid->point.x, solid->point.y, solid->point.z);
        dwgScene->addPoint(layerName, color, point);
    }
}

void DWGReader::convertRegionToScene(Dwg_Entity_REGION *region, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene) const
{
    if (!region)
        return;

    bool hasGeometry = false;

    // If we have wireframe data, use it for visualization
    if (region->num_wires > 0 && region->wires)
    {
        for (BITCODE_BL i = 0; i < region->num_wires; i++)
        {
            Dwg_3DSOLID_wire *wire = &region->wires[i];
            if (wire->num_points > 0 && wire->points)
            {
                std::vector<Vec3d> vertices;
                for (BITCODE_BL j = 0; j < wire->num_points; j++)
                {
                    vertices.push_back(Vec3d(wire->points[j].x, wire->points[j].y, wire->points[j].z));
                }
                dwgScene->addLineStrip(layerName, color, vertices);
                hasGeometry = true;
            }
        }
    }

    // If we have point data, draw a cross marker
    if (!hasGeometry && region->point_present)
    {
        Vec3d center(region->point.x, region->point.y, region->point.z);
        double size = 1.0; // Default size

        std::vector<Vec3d> crossLines;
        crossLines.push_back(Vec3d(center.x() - size, center.y(), center.z()));
        crossLines.push_back(Vec3d(center.x() + size, center.y(), center.z()));
        crossLines.push_back(Vec3d(center.x(), center.y() - size, center.z()));
        crossLines.push_back(Vec3d(center.x(), center.y() + size, center.z()));

        dwgScene->addLineStrip(layerName, color, crossLines);
    }
}

void DWGReader::convertDimensionLinearToScene(Dwg_Entity_DIMENSION_LINEAR *dim, const std::string &layerName,
                                              const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!dim)
        return;

    Vec3d defPoint(dim->def_pt.x, dim->def_pt.y, dim->def_pt.z);
    Vec3d xLine1Point(dim->xline1_pt.x, dim->xline1_pt.y, dim->xline1_pt.z);
    Vec3d xLine2Point(dim->xline2_pt.x, dim->xline2_pt.y, dim->xline2_pt.z);
    Vec3d textMidPoint(dim->text_midpt.x, dim->text_midpt.y, dim->elevation);

    // Get dimension text
    std::string dimTextValue;
    if (dim->user_text != nullptr && strlen(dim->user_text))
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)dim->user_text);
            dimTextValue = u8 ? std::string(u8) : "";
            if (u8)
                free(u8);
        }
        else
        {
            dimTextValue = std::string(dim->user_text);
        }
    }
    else
    {
        char buffer[32];
        sprintf(buffer, "%.2f", dim->act_measurement);
        dimTextValue = std::string(buffer);
    }

    double dimLength = (xLine2Point - xLine1Point).length();

    if (dimLength > 1e-10)
    {
        // Use dim_rotation field to determine dimension type and direction
        double dimRotation = dim->dim_rotation;
        bool isHorizontal = (fabs(dimRotation) < 1e-6 || fabs(dimRotation - M_PI) < 1e-6);
        bool isVertical = (fabs(dimRotation - M_PI / 2) < 1e-6 || fabs(dimRotation + M_PI / 2) < 1e-6);

        // Calculate the two endpoints of the dimension line
        Vec3d dimLineStart, dimLineEnd;

        if (isHorizontal)
        {
            // Horizontal dimension
            dimLineStart = Vec3d(xLine1Point.x(), defPoint.y(), defPoint.z());
            dimLineEnd = Vec3d(xLine2Point.x(), defPoint.y(), defPoint.z());
        }
        else if (isVertical)
        {
            // Vertical dimension
            dimLineStart = Vec3d(defPoint.x(), xLine1Point.y(), defPoint.z());
            dimLineEnd = Vec3d(defPoint.x(), xLine2Point.y(), defPoint.z());
        }
        else
        {
            // Rotated dimension - use dim_rotation to determine dimension line direction
            // The dimension line should pass through defPoint and be parallel to xLine1->xLine2
            double halfLength = dimLength * 0.5;

            // Calculate rotated dimension line endpoints
            double cosRot = cos(dimRotation);
            double sinRot = sin(dimRotation);

            Vec3d direction(cosRot, sinRot, 0.0);
            direction.normalize();

            dimLineStart = defPoint - direction * halfLength;
            dimLineEnd = defPoint + direction * halfLength;
        }

        Vec3d dimVector = dimLineEnd - dimLineStart;

        // Create dimension line
        std::vector<Vec3d> dimLineVertices;
        dimLineVertices.push_back(dimLineStart);
        dimLineVertices.push_back(dimLineEnd);
        dwgScene->addLineStrip(layerName, color, dimLineVertices);

        // Create extension lines (perpendicular lines from object points to dimension line)
        // First extension line
        Vec3d ext1Start = xLine1Point;
        Vec3d ext1End;
        if (isHorizontal)
        {
            ext1End = Vec3d(xLine1Point.x(), dimLineStart.y(), dimLineStart.z());
        }
        else if (isVertical)
        {
            ext1End = Vec3d(dimLineStart.x(), xLine1Point.y(), dimLineStart.z());
        }
        else
        {
            // Calculate foot of perpendicular
            Vec3d v = dimLineEnd - dimLineStart;
            Vec3d w = xLine1Point - dimLineStart;
            double c1 = v * w;
            double c2 = v * v;
            double b = c1 / c2;
            ext1End = dimLineStart + v * b;
        }

        std::vector<Vec3d> extLine1Vertices;
        extLine1Vertices.push_back(ext1Start);
        extLine1Vertices.push_back(ext1End);
        dwgScene->addLineStrip(layerName, color, extLine1Vertices);

        // Second extension line
        Vec3d ext2Start = xLine2Point;
        Vec3d ext2End;
        if (isHorizontal)
        {
            ext2End = Vec3d(xLine2Point.x(), dimLineEnd.y(), dimLineEnd.z());
        }
        else if (isVertical)
        {
            ext2End = Vec3d(dimLineEnd.x(), xLine2Point.y(), dimLineEnd.z());
        }
        else
        {
            // Calculate foot of perpendicular
            Vec3d v = dimLineEnd - dimLineStart;
            Vec3d w = xLine2Point - dimLineStart;
            double c1 = v * w;
            double c2 = v * v;
            double b = c1 / c2;
            ext2End = dimLineStart + v * b;
        }

        std::vector<Vec3d> extLine2Vertices;
        extLine2Vertices.push_back(ext2Start);
        extLine2Vertices.push_back(ext2End);
        dwgScene->addLineStrip(layerName, color, extLine2Vertices);

        // Get text height
        double textHeight = 1.0; // Default value
        Dwg_Object *dimStyleObj = dwg_ref_object(dwg, dim->dimstyle);
        if (dimStyleObj && dimStyleObj->fixedtype == DWG_TYPE_DIMSTYLE)
        {
            Dwg_Object_DIMSTYLE *dimStyle = dimStyleObj->tio.object->tio.DIMSTYLE;
            if (dimStyle->DIMTXT > 0)
            { // Ensure value is valid
                textHeight = dimStyle->DIMTXT;
            }
        }

        // Create arrows
        double arrowSize = textHeight * 0.8; // Use text height based arrow size

        // Create perpendicular vector (in XY plane)
        Vec3d perpVector(-dimVector.y(), dimVector.x(), 0.0);
        perpVector.normalize();

        // Start arrow
        std::vector<Vec3d> startArrow;
        startArrow.push_back(dimLineStart);
        startArrow.push_back(dimLineStart + dimVector * arrowSize - perpVector * arrowSize * 0.5);
        startArrow.push_back(dimLineStart + dimVector * arrowSize + perpVector * arrowSize * 0.5);
        startArrow.push_back(dimLineStart);
        dwgScene->addLineStrip(layerName, color, startArrow);

        // End arrow
        std::vector<Vec3d> endArrow;
        endArrow.push_back(dimLineEnd);
        endArrow.push_back(dimLineEnd - dimVector * arrowSize - perpVector * arrowSize * 0.5);
        endArrow.push_back(dimLineEnd - dimVector * arrowSize + perpVector * arrowSize * 0.5);
        endArrow.push_back(dimLineEnd);
        dwgScene->addLineStrip(layerName, color, endArrow);

        // Create OSG text for dimension
        ref_ptr<osgText::Text> dimText = new osgText::Text;
        dimText->setFont(font_);
        dimText->setText(dimTextValue);
        dimText->setPosition(textMidPoint);
        dimText->setAlignment(osgText::Text::CENTER_BOTTOM);
        dimText->setCharacterSize(arrowSize);
        dimText->setColor(color);

        // Set text rotation based on dimension direction
        if (!isHorizontal && !isVertical)
        {
            // Use dim_rotation field to set text rotation
            // Matrix rotationMatrix;
            // rotationMatrix.makeRotate(dimRotation, Vec3(0, 0, 1));
            // dimText->setRotation(Quat(rotationMatrix.getRotate()));
            dimText->setRotation(osg::Quat(dimRotation, osg::Vec3d(0,0,1)));
        }

        dwgScene->addText(layerName, color, textMidPoint, dimText);
    }
}

void DWGReader::convertDimensionAlignedToScene(Dwg_Entity_DIMENSION_ALIGNED *dim, const std::string &layerName,
                                               const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!dim)
        return;

    Vec3d defPoint(dim->def_pt.x, dim->def_pt.y, dim->def_pt.z);
    Vec3d xLine1Point(dim->xline1_pt.x, dim->xline1_pt.y, dim->xline1_pt.z);
    Vec3d xLine2Point(dim->xline2_pt.x, dim->xline2_pt.y, dim->xline2_pt.z);
    Vec3d textMidPoint(dim->text_midpt.x, dim->text_midpt.y,dim->elevation);

    // Get dimension text
    std::string dimTextValue;
    if (dim->user_text != nullptr && strlen(dim->user_text))
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)dim->user_text);
            dimTextValue = u8 ? std::string(u8) : "";
            if (u8)
                free(u8);
        }
        else
        {
            dimTextValue = std::string(dim->user_text);
        }
    }
    else
    {
        char buffer[32];
        sprintf(buffer, "%.2f", dim->act_measurement);
        dimTextValue = std::string(buffer);
    }

    // Calculate vector between two points
    Vec3d dimVector = xLine2Point - xLine1Point;
    double dimLength = dimVector.length();

    if (dimLength > 1e-10)
    {
        dimVector.normalize();

        // Correctly calculate dimension line position
        // 1. Calculate vector from xLine1Point to defPoint
        Vec3d toDefPoint = defPoint - xLine1Point;

        // 2. Project this vector onto dimVector direction to get position along dimension line
        double projectionLength = toDefPoint * dimVector;

        // 3. Calculate offset distance perpendicular to dimension line
        Vec3d projectedPoint = xLine1Point + dimVector * projectionLength;
        double offsetDistance = (defPoint - projectedPoint).length();

        // 4. Determine offset direction (ensure dimension line is near defPoint)
        Vec3d perpendicular = (defPoint - projectedPoint);
        if (perpendicular.length() > 1e-10)
        {
            perpendicular.normalize();
        }
        else
        {
            // If defPoint is exactly on the xLine1-xLine2 line, create a perpendicular vector
            if (fabs(dimVector.x()) > fabs(dimVector.y()))
            {
                perpendicular = Vec3d(-dimVector.y(), dimVector.x(), 0.0);
            }
            else
            {
                perpendicular = Vec3d(0.0, -dimVector.z(), dimVector.y());
            }
            perpendicular.normalize();
        }

        // 5. Calculate the two endpoints of the dimension line
        Vec3d dimLineStart = xLine1Point + perpendicular * offsetDistance;
        Vec3d dimLineEnd = xLine2Point + perpendicular * offsetDistance;

        // Create dimension line
        std::vector<Vec3d> dimLineVertices;
        dimLineVertices.push_back(dimLineStart);
        dimLineVertices.push_back(dimLineEnd);
        dwgScene->addLineStrip(layerName, color, dimLineVertices);

        // Create extension lines (perpendicular lines from object points to dimension line)
        // First extension line
        Vec3d ext1Start = xLine1Point;
        Vec3d ext1End = dimLineStart;

        std::vector<Vec3d> extLine1Vertices;
        extLine1Vertices.push_back(ext1Start);
        extLine1Vertices.push_back(ext1End);
        dwgScene->addLineStrip(layerName, color, extLine1Vertices);

        // Second extension line
        Vec3d ext2Start = xLine2Point;
        Vec3d ext2End = dimLineEnd;

        std::vector<Vec3d> extLine2Vertices;
        extLine2Vertices.push_back(ext2Start);
        extLine2Vertices.push_back(ext2End);
        dwgScene->addLineStrip(layerName, color, extLine2Vertices);

        // Create arrows
        double arrowSize = std::max(dimLength * 0.03, 0.5);

        // Create perpendicular vector (in XY plane)
        Vec3d perpVector(-dimVector.y(), dimVector.x(), 0.0);
        perpVector.normalize();

        // Start arrow
        std::vector<Vec3d> startArrow;
        startArrow.push_back(dimLineStart);
        startArrow.push_back(dimLineStart + dimVector * arrowSize - perpVector * arrowSize * 0.5);
        startArrow.push_back(dimLineStart + dimVector * arrowSize + perpVector * arrowSize * 0.5);
        startArrow.push_back(dimLineStart);
        dwgScene->addLineStrip(layerName, color, startArrow);

        // End arrow
        std::vector<Vec3d> endArrow;
        endArrow.push_back(dimLineEnd);
        endArrow.push_back(dimLineEnd - dimVector * arrowSize - perpVector * arrowSize * 0.5);
        endArrow.push_back(dimLineEnd - dimVector * arrowSize + perpVector * arrowSize * 0.5);
        endArrow.push_back(dimLineEnd);
        dwgScene->addLineStrip(layerName, color, endArrow);

        // Calculate dimension line angle
        double dimAngle = atan2(dimVector.y(), dimVector.x());

        // Normalize angle to -90° to 90° range for better readability
        while (dimAngle > M_PI / 2)
            dimAngle -= M_PI;
        while (dimAngle < -M_PI / 2)
            dimAngle += M_PI;

        // Create OSG text for dimension
        ref_ptr<osgText::Text> dimText = new osgText::Text;
        dimText->setFont(font_);
        dimText->setText(dimTextValue);
        dimText->setPosition(textMidPoint);
        dimText->setAlignment(osgText::Text::CENTER_BOTTOM);
        dimText->setCharacterSize(arrowSize);
        dimText->setColor(color);

        // Set text rotation
        // Matrix rotationMatrix;
        // rotationMatrix.makeRotate(dimAngle, Vec3(0, 0, 1));
        // dimText->setRotation(Quat(rotationMatrix.getRotate()));
        dimText->setRotation(osg::Quat(dimAngle, osg::Vec3d(0,0,1)));
        dwgScene->addText(layerName, color, textMidPoint, dimText);
    }
}

void DWGReader::convertDimensionAng2LnToScene(Dwg_Entity_DIMENSION_ANG2LN *dim, const std::string &layerName,
                                              const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!dim)
        return;

    Vec3d xLine1Start(dim->xline1start_pt.x, dim->xline1start_pt.y, dim->xline1start_pt.z);
    Vec3d xLine1End(dim->xline1end_pt.x, dim->xline1end_pt.y, dim->xline1end_pt.z);
    Vec3d defPoint(dim->def_pt.x, dim->def_pt.y, dim->def_pt.z);
    Vec3d xLine2Start(dim->xline2start_pt.x, dim->xline2start_pt.y, dim->xline2start_pt.z);
    Vec3d xLine2End(dim->xline2end_pt.x, dim->xline2end_pt.y, dim->xline2end_pt.z);
    Vec3d textMidPoint(dim->text_midpt.x, dim->text_midpt.y, dim->elevation);

    // Get dimension text
    std::string dimTextValue;
    if (dim->user_text != nullptr && strlen(dim->user_text))
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)dim->user_text);
            dimTextValue = u8 ? std::string(u8) : "";
            if (u8)
                free(u8);
        }
        else
        {
            dimTextValue = std::string(dim->user_text);
        }
    }
    else
    {
        // Calculate vectors of two lines
        Vec3d line1Vec = xLine1End - xLine1Start;
        Vec3d line2Vec = xLine2Start - xLine2End; // Second line from xline2start_pt to xline2end_pt

        line1Vec.normalize();
        line2Vec.normalize();

        // Calculate angle
        double dotProduct = line1Vec * line2Vec;
        // Limit to [-1, 1] range to prevent calculation errors
        dotProduct = std::max(-1.0, std::min(1.0, dotProduct));
        double angleRad = acos(dotProduct);
        double angleDeg = angleRad * 180.0 / M_PI;

        char buffer[32];
        sprintf(buffer, "%.2f°", angleDeg);
        dimTextValue = std::string(buffer);
    }

    // Calculate vectors of two lines
    Vec3d line1Vec = xLine1End - xLine1Start;
    Vec3d line2Vec = xLine2Start - xLine2End; // Second line from xline2start_pt to xline2end_pt

    line1Vec.normalize();
    line2Vec.normalize();

    // Use xLine2End as arc center point
    Vec3d arcCenter = xLine2End;

    // Calculate arc radius (based on distance from defPoint to arc center)
    double arcRadius = (arcCenter - defPoint).length();
    arcRadius = std::max(arcRadius, 5.0); // Set minimum radius

    // Calculate angle
    double dotProduct = line1Vec * line2Vec;
    dotProduct = std::max(-1.0, std::min(1.0, dotProduct));
    double angle = acos(dotProduct);

    if (angle > 1e-10 && angle < M_PI - 1e-10)
    { // Ensure angle is not 0 or 180 degrees
        // Calculate angles of two lines relative to center point
        double angle1 = atan2(line1Vec.y(), line1Vec.x());
        double angle2 = atan2(line2Vec.y(), line2Vec.x());

        // Normalize angles to [0, 2π]
        while (angle1 < 0)
            angle1 += 2 * M_PI;
        while (angle2 < 0)
            angle2 += 2 * M_PI;

        // Ensure we draw the smaller angle (right-hand rule, counterclockwise angle from line 1 to line 2)
        double angleDiff = fabs(angle2 - angle1);
        if (angleDiff > M_PI)
        {
            // If angle difference is greater than 180 degrees, we need to adjust angles to ensure we draw the smaller angle
            if (angle1 < angle2)
                angle1 += 2 * M_PI;
            else
                angle2 += 2 * M_PI;
        }

        // Ensure angle1 is start angle, angle2 is end angle (counterclockwise direction)
        if (angle1 > angle2)
            std::swap(angle1, angle2);

        double angleRange = angle2 - angle1;

        // Create arc vertices
        std::vector<Vec3d> arcVertices;
        int segments = std::max(32, (int)(angleRange * 30));

        for (int i = 0; i <= segments; i++)
        {
            double t = (double)i / segments;
            double currentAngle = angle1 + t * angleRange;
            Vec3d point(arcCenter.x() + arcRadius * cos(currentAngle),
                        arcCenter.y() + arcRadius * sin(currentAngle),
                        arcCenter.z());
            arcVertices.push_back(point);
        }

        // Create angle dimension arc
        dwgScene->addLineStrip(layerName, color, arcVertices);

        // Create extension lines (short lines from arc center to arc endpoints)
        double extensionLineLength = arcRadius * 0.2;

        // First extension line
        Vec3d arcStart(arcCenter.x() + arcRadius * cos(angle1),
                       arcCenter.y() + arcRadius * sin(angle1),
                       arcCenter.z());
        Vec3d extensionEnd1 = arcStart + line1Vec * extensionLineLength;

        std::vector<Vec3d> extLine1Vertices;
        extLine1Vertices.push_back(arcStart);
        extLine1Vertices.push_back(extensionEnd1);
        dwgScene->addLineStrip(layerName, color, extLine1Vertices);

        // Second extension line
        Vec3d arcEnd(arcCenter.x() + arcRadius * cos(angle2),
                     arcCenter.y() + arcRadius * sin(angle2),
                     arcCenter.z());
        Vec3d extensionEnd2 = arcEnd + line2Vec * extensionLineLength;

        std::vector<Vec3d> extLine2Vertices;
        extLine2Vertices.push_back(arcEnd);
        extLine2Vertices.push_back(extensionEnd2);
        dwgScene->addLineStrip(layerName, color, extLine2Vertices);

        // Get text height
        double textHeight = 1.0; // Default value
        Dwg_Object *dimStyleObj = dwg_ref_object(dwg, dim->dimstyle);
        if (dimStyleObj && dimStyleObj->fixedtype == DWG_TYPE_DIMSTYLE)
        {
            Dwg_Object_DIMSTYLE *dimStyle = dimStyleObj->tio.object->tio.DIMSTYLE;
            if (dimStyle->DIMTXT > 0)
            { // Ensure value is valid
                textHeight = dimStyle->DIMTXT;
            }
        }

        // Create arrows (along arc direction)
        double arrowSize = textHeight * 0.8;

        // Start arrow (along arc tangent direction)
        double startTangentAngle = angle1 - M_PI / 2; // Tangent direction perpendicular to radius direction
        Vec3d startTangent(cos(startTangentAngle), sin(startTangentAngle), 0.0);
        startTangent.normalize();

        std::vector<Vec3d> startArrow;
        startArrow.push_back(arcStart);
        startArrow.push_back(arcStart - startTangent * arrowSize * 0.7 - Vec3d(cos(angle1), sin(angle1), 0) * arrowSize * 0.3);
        startArrow.push_back(arcStart - startTangent * arrowSize * 0.7 + Vec3d(cos(angle1), sin(angle1), 0) * arrowSize * 0.3);
        startArrow.push_back(arcStart);
        dwgScene->addLineStrip(layerName, color, startArrow);

        // End arrow (along arc tangent direction)
        double endTangentAngle = angle2 - M_PI / 2; // Tangent direction perpendicular to radius direction
        Vec3d endTangent(cos(endTangentAngle), sin(endTangentAngle), 0.0);
        endTangent.normalize();

        std::vector<Vec3d> endArrow;
        endArrow.push_back(arcEnd);
        endArrow.push_back(arcEnd - endTangent * arrowSize * 0.7 - Vec3d(cos(angle2), sin(angle2), 0) * arrowSize * 0.3);
        endArrow.push_back(arcEnd - endTangent * arrowSize * 0.7 + Vec3d(cos(angle2), sin(angle2), 0) * arrowSize * 0.3);
        endArrow.push_back(arcEnd);
        dwgScene->addLineStrip(layerName, color, endArrow);

        // Calculate tangent angle at text position for text rotation
        // First calculate text angle position on arc
        double textAngle = atan2(textMidPoint.y() - arcCenter.y(), textMidPoint.x() - arcCenter.x());
        // Normalize angle
        while (textAngle < 0)
            textAngle += 2 * M_PI;

        // Calculate tangent angle (perpendicular to radius direction)
        double textTangentAngle = textAngle + M_PI / 2;

        // Create OSG text for dimension
        ref_ptr<osgText::Text> dimText = new osgText::Text;
        dimText->setFont(font_);
        dimText->setText(dimTextValue);
        dimText->setPosition(textMidPoint);
        dimText->setAlignment(osgText::Text::CENTER_BOTTOM);
        dimText->setCharacterSize(textHeight);

        // Create rotation matrix
        // Matrix rotationMatrix;
        // rotationMatrix.makeRotate(textTangentAngle, Vec3(0, 0, 1));
        // dimText->setRotation(Quat(rotationMatrix.getRotate()));
        dimText->setRotation(osg::Quat(textTangentAngle, osg::Vec3d(0,0,1)));
        dimText->setColor(color);

        dwgScene->addText(layerName, color, textMidPoint, dimText);
    }
}

void DWGReader::convertDimensionOrdinateToScene(Dwg_Entity_DIMENSION_ORDINATE *dim, const std::string &layerName,
                                                const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!dim)
        return;

    Vec3d defPoint(dim->def_pt.x, dim->def_pt.y, dim->def_pt.z);
    Vec3d featureLocation(dim->feature_location_pt.x, dim->feature_location_pt.y, dim->feature_location_pt.z);
    Vec3d leaderEndpoint(dim->leader_endpt.x, dim->leader_endpt.y, dim->leader_endpt.z);
    Vec3d textMidPoint(dim->text_midpt.x, dim->text_midpt.y, dim->elevation);

    // Get dimension text
    std::string dimTextValue;
    if (dim->user_text != nullptr && strlen(dim->user_text))
    {
        if (dwg->header.version >= R_2007)
        {
            char *u8 = bit_convert_TU((BITCODE_TU)dim->user_text);
            dimTextValue = u8 ? std::string(u8) : "";
            if (u8)
                free(u8);
        }
        else
        {
            dimTextValue = std::string(dim->user_text);
        }
    }
    else
    {
        // Calculate coordinate value
        char buffer[32];
        if (dim->flag2 & 1)
        { // Use X axis
            sprintf(buffer, "X=%.2f", featureLocation.x());
        }
        else
        { // Use Y axis
            sprintf(buffer, "Y=%.2f", featureLocation.y());
        }
        dimTextValue = std::string(buffer);
    }

    // Create leader point list - follow CAD standard leader drawing rules
    std::vector<Vec3d> leaderPoints;
    leaderPoints.push_back(featureLocation);

    // According to CAD standard rules to determine leader path:
    // 1. If it is X-type coordinate dimension, measure X coordinate value, leader extends along Y direction first
    // 2. If it is Y-type coordinate dimension, measure Y coordinate value, leader extends along X direction first
    bool isXType = (dim->flag2 & 1); // X-type if set, else Y-type

    if (isXType)
    {
        // X-type dimension: measure X coordinate, leader extends vertically (Y direction) first, then horizontally to text
        if (fabs(featureLocation.y() - textMidPoint.y()) > 1e-10)
        {
            Vec3d verticalEnd(featureLocation.x(), textMidPoint.y(), 0.0);
            leaderPoints.push_back(verticalEnd);
        }

        // Add horizontal connection to text
        if (fabs(featureLocation.x() - textMidPoint.x()) > 1e-10)
        {
            Vec3d horizontalEnd(textMidPoint.x(), textMidPoint.y(), 0.0);
            leaderPoints.push_back(horizontalEnd);
        }
    }
    else
    {
        // Y-type dimension: measure Y coordinate, leader extends horizontally (X direction) first, then vertically to text
        if (fabs(featureLocation.x() - textMidPoint.x()) > 1e-10)
        {
            Vec3d horizontalEnd(textMidPoint.x(), featureLocation.y(), 0.0);
            leaderPoints.push_back(horizontalEnd);
        }

        // Add vertical connection to text
        if (fabs(featureLocation.y() - textMidPoint.y()) > 1e-10)
        {
            Vec3d verticalEnd(textMidPoint.x(), textMidPoint.y(), 0.0);
            leaderPoints.push_back(verticalEnd);
        }
    }

    // If calculated leader points only have start point, add end point
    if (leaderPoints.size() == 1)
    {
        leaderPoints.push_back(textMidPoint);
    }

    // Create leader line
    dwgScene->addLineStrip(layerName, color, leaderPoints);

    // Get text height
    double textHeight = 1.0; // Default value
    Dwg_Object *dimStyleObj = dwg_ref_object(dwg, dim->dimstyle);
    if (dimStyleObj && dimStyleObj->fixedtype == DWG_TYPE_DIMSTYLE)
    {
        Dwg_Object_DIMSTYLE *dimStyle = dimStyleObj->tio.object->tio.DIMSTYLE;
        if (dimStyle->DIMTXT > 0)
        { // Ensure value is valid
            textHeight = dimStyle->DIMTXT;
        }
    }

    // Create OSG text for dimension
    ref_ptr<osgText::Text> dimText = new osgText::Text;
    dimText->setFont(font_);
    dimText->setText(dimTextValue);
    dimText->setPosition(textMidPoint);
    dimText->setCharacterSize(textHeight);
    dimText->setColor(color);
    dimText->setAlignment(osgText::Text::CENTER_BOTTOM);

    dwgScene->addText(layerName, color, textMidPoint, dimText);

    // Create arrow (at leader endpoint)
    double arrowSize = 0.5;
    Vec3d arrowDirection = leaderEndpoint - featureLocation;
    if (arrowDirection.length() > 1e-10)
    {
        arrowDirection.normalize();

        // Create perpendicular vector (in XY plane)
        Vec3d perpVector(-arrowDirection.y(), arrowDirection.x(), 0.0);
        perpVector.normalize();

        // Arrow
        std::vector<Vec3d> arrow;
        arrow.push_back(leaderEndpoint);
        arrow.push_back(leaderEndpoint - arrowDirection * arrowSize - perpVector * arrowSize * 0.5);
        arrow.push_back(leaderEndpoint - arrowDirection * arrowSize + perpVector * arrowSize * 0.5);
        arrow.push_back(leaderEndpoint);
        dwgScene->addLineStrip(layerName, color, arrow);
    }
}

void DWGReader::convertSplineToScene(Dwg_Entity_SPLINE *spline, const std::string &layerName,
                                     const Vec4 &color, DwgScene *dwgScene) const
{
    if (!spline)
        return;

    std::vector<Vec3d> pts;

    /* 1. 完整 NURBS路径 */
    if (spline->num_knots > 0 && spline->num_ctrl_pts > 0 &&
        spline->knots && spline->ctrl_pts)
    {
        std::vector<double> tmpKnots;
        const double *U = spline->knots;
        int uCount = spline->num_knots;
        if (!U || uCount == 0)
        {
            tmpKnots = make_clamped_uniform(spline->degree, spline->num_ctrl_pts);
            U = tmpKnots.data();
            uCount = (int)tmpKnots.size();
        }
        pts = tessellate_nurbs(*spline, U, uCount, 400);
    }
    /* 2. 降级：只用 fit_pts */
    else if (spline->num_fit_pts > 0 && spline->fit_pts)
    {
        pts = tessellate_fit_catmull(*spline, 4);
    }

    if (!pts.empty())
    {
        dwgScene->addLineStrip(layerName, color, pts);
    }
}

void DWGReader::convertXLineToScene(Dwg_Entity_XLINE *xline, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene) const
{
    if (!xline)
        return;

    Vec3d basePoint(xline->point.x, xline->point.y, xline->point.z);
    Vec3d directionVector(xline->vector.x, xline->vector.y, xline->vector.z);

    // Normalize direction vector
    double length = directionVector.length();
    if (length == 0.0)
    {
        return;
    }
    directionVector.normalize();

    // Create a long line segment to simulate infinite line
    double lineLength = 10000.0;
    Vec3d startPoint = basePoint - directionVector * lineLength;
    Vec3d endPoint = basePoint + directionVector * lineLength;

    std::vector<Vec3d> points;
    points.push_back(startPoint);
    points.push_back(endPoint);

    dwgScene->addLineStrip(layerName, color, points);
}

void DWGReader::convertRayToScene(Dwg_Entity_RAY *ray, const std::string &layerName,
                                  const Vec4 &color, DwgScene *dwgScene) const
{
    if (!ray)
        return;

    Vec3d basePoint(ray->point.x, ray->point.y, ray->point.z);
    Vec3d directionVector(ray->vector.x, ray->vector.y, ray->vector.z);

    // Normalize direction vector
    double length = directionVector.length();
    if (length == 0.0)
    {
        return;
    }
    directionVector.normalize();

    // Create a long line segment to simulate infinite ray
    double lineLength = 10000.0;
    Vec3d endPoint = basePoint + directionVector * lineLength;

    std::vector<Vec3d> points;
    points.push_back(basePoint);
    points.push_back(endPoint);

    dwgScene->addLineStrip(layerName, color, points);
}

void DWGReader::convertPolyline3DToScene(Dwg_Object *entity, const std::string &layerName,
                                         const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!entity || !entity->tio.entity)
        return;
    if (!entity->tio.entity->tio.POLYLINE_3D)
        return;
    std::vector<Vec3d> points;
    Dwg_Entity_POLYLINE_3D *polyline3d = entity->tio.entity->tio.POLYLINE_3D;
    // Extract vertices from owned entities
    Dwg_Object *vertexObj = get_first_owned_subentity(entity);
    while (vertexObj)
    {
        if (vertexObj->fixedtype == DWG_TYPE_VERTEX_3D)
        {
            Dwg_Entity_VERTEX_3D *vertex = vertexObj->tio.entity->tio.VERTEX_3D;
            if (vertex)
            {
                Vec3d point(vertex->point.x, vertex->point.y, vertex->point.z);
                points.push_back(point);
            }
        }
        vertexObj = get_next_owned_subentity(entity, vertexObj);
    }

    if (points.empty())
        return;

    // Handle closed polyline
    if (polyline3d->flag & 1)
    { // Closed polyline
        dwgScene->addLineLoop(layerName, color, points);
    }
    else
    {
        dwgScene->addLineStrip(layerName, color, points);
    }
}

void DWGReader::convertEllipseToScene(Dwg_Entity_ELLIPSE *ellipse, const std::string &layerName,
                                      const Vec4 &color, DwgScene *dwgScene) const
{
    if (!ellipse)
        return;

    Vec3d center(ellipse->center.x, ellipse->center.y, ellipse->center.z);
    Vec3d majorAxis(ellipse->sm_axis.x, ellipse->sm_axis.y, ellipse->sm_axis.z);

    double majorRadius = majorAxis.length();
    double minorRadius = majorRadius * ellipse->axis_ratio;
    double rotationAngle = atan2(majorAxis.y(), majorAxis.x());

    double startAngle = ellipse->start_angle;
    double endAngle = ellipse->end_angle;

    // If it's a full ellipse
    bool isFullEllipse = (startAngle == endAngle);
    if (isFullEllipse)
    {
        startAngle = 0.0;
        endAngle = 2.0 * M_PI;
    }

    // Normalize angles
    while (endAngle < startAngle)
        endAngle += 2.0 * M_PI;

    // Create ellipse vertices
    std::vector<Vec3d> vertices;
    int segments = 32;
    double angleRange = endAngle - startAngle;
    int actualSegments = isFullEllipse ? segments : std::max(8, (int)(segments * angleRange / (2.0 * M_PI)));

    for (int i = 0; i <= actualSegments; ++i)
    {
        double angle = startAngle + angleRange * i / actualSegments;

        // Ellipse parametric equation
        double x = majorRadius * cos(angle);
        double y = minorRadius * sin(angle);

        // Apply rotation
        double rotatedX = x * cos(rotationAngle) - y * sin(rotationAngle);
        double rotatedY = x * sin(rotationAngle) + y * cos(rotationAngle);

        // Translate to center position
        Vec3d point(center.x() + rotatedX, center.y() + rotatedY, center.z());
        vertices.push_back(point);
    }

    // If it's a full ellipse, ensure it's closed
    if (isFullEllipse && !vertices.empty())
    {
        vertices.push_back(vertices[0]);
    }

    dwgScene->addLineStrip(layerName, color, vertices);
}

void DWGReader::convertMLineToScene(Dwg_Entity_MLINE *mline, const std::string &layerName,
                                    const Vec4 &color, DwgScene *dwgScene, Dwg_Data *dwg) const
{
    if (!mline || !mline->verts || mline->num_verts < 2)
        return;

    // Extract vertices for each line in the MLINE
    for (BITCODE_RC lineIdx = 0; lineIdx < mline->num_lines; ++lineIdx)
    {
        std::vector<Vec3d> points;

        // Extract points for this line
        for (BITCODE_BS v = 0; v < mline->num_verts; ++v)
        {
            Dwg_MLINE_vertex &vert = mline->verts[v];
            if (lineIdx < vert.num_lines)
            {
                Dwg_MLINE_line &line = vert.lines[lineIdx];

                // If segparms exist, use the first one as validation point
                if (line.num_segparms > 0)
                {
                    double d = line.segparms[0];
                    Vec3d pos(
                        vert.vertex.x + vert.miter_direction.x * d,
                        vert.vertex.y + vert.miter_direction.y * d,
                        vert.vertex.z + vert.miter_direction.z * d);
                    points.push_back(pos);
                }
                else
                {
                    // Otherwise use vertex coordinates directly
                    Vec3d pos(vert.vertex.x, vert.vertex.y, vert.vertex.z);
                    points.push_back(pos);
                }
            }
        }

        if (!points.empty())
        {
            // Handle closed MLINE
            bool isClosed = (mline->flags & 1) != 0;
            if (isClosed)
            {
                dwgScene->addLineLoop(layerName, color, points);
            }
            else
            {
                dwgScene->addLineStrip(layerName, color, points);
            }
        }
    }
}

void DWGReader::convertToleranceToScene(Dwg_Entity_TOLERANCE *tolerance, const std::string &layerName,
                                        const Vec4 &color, DwgScene *dwgScene) const
{
    if (!tolerance)
        return;

    // Get insertion point
    Vec3d insertPoint(tolerance->ins_pt.x, tolerance->ins_pt.y, tolerance->ins_pt.z);

    // Create text content
    std::string textContent;
    if (tolerance->text_value)
    {
        textContent = std::string(tolerance->text_value);
    }
    else
    {
        textContent = "TOLERANCE";
    }

    // Create OSG text
    ref_ptr<osgText::Text> osgText = new osgText::Text;
    osgText->setFont(font_);
    osgText->setText(textContent);
    osgText->setPosition(insertPoint);
    osgText->setCharacterSize(tolerance->height > 0 ? tolerance->height : 1.0);
    osgText->setColor(color);
    osgText->setAlignment(osgText::Text::LEFT_TOP);

    dwgScene->addText(layerName, color, insertPoint, osgText);
}

Vec4 DWGReader::convertColor(Dwg_Object_Entity *ent, Dwg_Data *dwg) const
{
    // TODO: alpha?
    if (ent->color.index >= 8 && ent->color.index < 256)
    {
        const Dwg_RGB_Palette *palette = dwg_rgb_palette();
        const Dwg_RGB_Palette *rgb = &palette[ent->color.index];
        return Vec4(rgb->r / 255.0, rgb->g / 255.0, rgb->b / 255.0, 1);
    }
    else if (ent->color.flag & 0x80 && !(ent->color.flag & 0x40))
    {
        unsigned int rgbValue = ent->color.rgb & 0x00ffffff;
        unsigned char red = (rgbValue >> 16) & 0xFF;  // 提取红色分量
        unsigned char green = (rgbValue >> 8) & 0xFF; // 提取绿色分量
        unsigned char blue = rgbValue & 0xFF;         // 提取蓝色分量
        return Vec4(red / 255.0, green / 255.0, blue / 255.0, 1);
    }
    else
        switch (ent->color.index)
        {
        case 1:
            return Vec4(1.0f, 0.0f, 0.0f, 1.0f);
        case 2:
            return Vec4(1.0f, 1.0f, 0.0f, 1.0f);
        case 3:
            return Vec4(0.0f, 1.0f, 0.0f, 1.0f);
        case 4:
            return Vec4(0.0f, 1.0f, 1.0f, 1.0f);
        case 5:
            return Vec4(0.0f, 0.0f, 1.0f, 1.0f);
        case 6:
            return Vec4(1.0f, 0.0f, 1.0f, 1.0f);
        case 7:
            return Vec4(1.0f, 1.0f, 1.0f, 1.0f);
        case 0: // ByBlock
        {
            // 当实体颜色设置为ByBlock时，应该使用BLOCK的颜色
            // 在当前上下文中，我们无法直接访问BLOCK的颜色，
            // 所以返回默认颜色（白色）
            return Vec4(1.0f, 1.0f, 1.0f, 1.0f);
        }
        case 256: // ByLayer
        {
            // 当实体颜色设置为ByLayer时，应该使用图层的颜色
            // 获取实体所属的图层对象
            if (ent->layer)
            {
                Dwg_Object *layerObj = dwg_ref_object(ent->dwg, ent->layer);
                if (layerObj && layerObj->fixedtype == DWG_TYPE_LAYER)
                {
                    Dwg_Object_LAYER *layer = layerObj->tio.object->tio.LAYER;
                    Dwg_Object_Entity layerEntity;
                    memset(&layerEntity, 0, sizeof(Dwg_Object_Entity));
                    layerEntity.color = layer->color;
                    if (layer->color.method == 0xc3)
                    {
                        layerEntity.color.index = layer->color.rgb & 0x00ffffff;
                    }
                    return convertColor(&layerEntity, dwg);
                }
            }
            // 如果无法获取图层颜色，返回默认黑色
            return Vec4(0.0f, 0.0f, 0.0f, 1.0f);
        }
        default:
            return Vec4(0.0f, 0.0f, 0.0f, 1.0f);
        }
}